local modname = "wechat_proxy"
local _M = { _VERSION = '0.0.1' }
_G[modname] = _M

local cjson = require("cjson")

local ngx_re_sub = ngx.re.sub
local ngx_re_match = ngx.re.match
local ngx_req_set_uri = ngx.req.set_uri
local ngx_req_get_uri_args = ngx.req.get_uri_args
local ngx_req_set_uri_args = ngx.req.set_uri_args

local ngx_req = ngx.req
local ngx_log = ngx.log
local ngx_print = ngx.print
local ngx_exit = ngx.exit

local inspect = require("resty.wechat.utils.inspect")

--local resty_url = require("resty.wechat.utils.resty_url")

--local accessTokenKey = wechat_config.accessTokenKey or ("access_token:" .. wechat_config.appid)

local function _verify_request_params(params)
  if not params.app_key then
    return nil, "missing app_key"
  end
  if not params.proxy_uri then
    return nil, "missing proxy_uri"
  end
  return true
end

local mt = {
  __call = function(_, location_root)
    ngx_log(ngx.INFO, "location_root=" .. location_root)
    --local normalize_uri = resty_url.normalize(ngx.var.uri)
    ngx_log(ngx.INFO, "ngx.var.uri=" .. ngx.var.uri )
    --ngx_log(ngx.INFO, "normalize_uri=" .. normalize_uri )
    local m, err = ngx_re_match(ngx.var.uri, "^/" .. location_root .. "/([a-z]+)(/.+)", "jo")
    if not m then
      if err then
        ngx_print(cjson.encode({ errmsg = "uri : " .. ngx.var.uri .. " match err : " .. err }))
        return ngx_exit(ngx.HTTP_OK)
      end
      ngx_print(cjson.encode({ errmsg = "url : " .. ngx.var.uri .. " match not found" }))
      return ngx_exit(ngx.HTTP_OK)
    else
      local params = {
        app_key = m[1],
        proxy_uri = m[2]
      }

      ngx_log(ngx.INFO, "inspect params = " .. inspect(params))

      local ok, err = _verify_request_params(params)

      if not ok then
        ngx_print(cjson.encode({ errmsg = "failed to verify request: " .. err }))
        return ngx_exit(ngx.HTTP_OK)
      end

      ngx_req_set_uri(params.proxy_uri)

      local red = require("resty.wechat.utils.redis"):connect(wechat_config.redis).redis

      local access_token_key = "access_token:" .. params.app_key
      local access_token = red:get(access_token_key)

      ngx_log(ngx.INFO, "access_token = " .. inspect(access_token))

      if access_token == ngx.null then
        ngx_print(cjson.encode({ errmsg = "access_token_key:[" .. access_token_key .. "] not found in redis !" }))
        return ngx_exit(ngx.HTTP_OK)
      end

      ngx_log(ngx.INFO, "proxy_uri = " .. inspect(proxy_uri))

      if params.proxy_uri == "/cgi-bin/token" then
        local access_token_expire_time = red:ttl(access_token_key)
        ngx_print(cjson.encode({ access_token = access_token, expires_in = access_token_expire_time }))
        return ngx_exit(ngx.HTTP_OK)
      end

      if params.proxy_uri == "/cgi-bin/ticket/getticket" then
        local ticket_key = "ticket:" .. params.app_key
        local ticket = red:get(ticket_key)

        ngx_log(ngx.INFO, "ticket = " .. inspect(ticket))

        if ticket == ngx.null then
          ngx_print(cjson.encode({ errmsg = "ticket_key:[" .. ticket_key .. "] not found in redis !" }))
          return ngx_exit(ngx.HTTP_OK)
        end

        local ticket_expire_time = red:ttl(ticket_key)

        ngx_print(cjson.encode({ ticket = ticket, expires_in = ticket_expire_time }))
        return ngx_exit(ngx.HTTP_OK)
      end

      local args = ngx_req_get_uri_args()

      args["access_token"] = access_token

      ngx_req_set_uri_args(args)

      ngx_log(ngx.INFO, "redirect uri = [" .. inspect(ngx.var.uri) .. "] , param = [" .. inspect(ngx.var.args) .. "]")

      --ngx.var.backend_host = "api.weixin.qq.com"

    end
  end,
}

return setmetatable(_M, mt)
